﻿using System;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using K9Nano.Share.Exceptions;

namespace K9Nano.Domain
{
    public interface IUnitOfWork
    {
        IRepository<TEntity, TKey> Repository<TEntity, TKey>() where TEntity : class, IEntity<TKey> where TKey : IEquatable<TKey>;
        IRepository<TEntity> Repository<TEntity>() where TEntity : Entity;
        //void SaveChanges(bool acceptAllChangesOnSuccess = true);
        //Task SaveChangesAsync(bool acceptAllChangesOnSuccess = true, CancellationToken cancellation = default);
        IDisposable DisableFilters();
        IDisposable DisableAutoSetTenant();
        IDisposable DisableEvents();
        void BeginTransaction();
        void Commit();
        void Rollback();

        void RunTransaction([NotNull] Action action)
        {
            BeginTransaction();

            try
            {
                action();
                Commit();
            }
            catch
            {
                Rollback();
                throw;
            }
        }

        async ValueTask RunTransactionAsync([NotNull] Func<Task> action)
        {
            BeginTransaction();
            try
            {
                await action();
                Commit();
            }
            catch
            {
                Rollback();
                throw;
            }
        }


        T RunTransaction<T>([NotNull] Func<T> action)
        {
            var tName = typeof(T).FullName;
            if (tName == null 
                || tName.StartsWith("System.Threading.Tasks.Task")
                || tName.StartsWith("System.Threading.Tasks.ValueTask"))
            {
                throw new K9Exception("请使用RunTransactionAsync");
            }
            BeginTransaction();

            try
            {
                var result = action();
                Commit();
                return result;
            }
            catch
            {
                Rollback();
                throw;
            }
        }

        async ValueTask<T> RunTransactionAsync<T>([NotNull] Func<Task<T>> action)
        {
            BeginTransaction();
            try
            {
                var result = await action();
                Commit();
                return result;
            }
            catch
            {
                Rollback();
                throw;
            }
        }
    }
}